#include <filesystem>
#include <cstdio>
#include <fstream>
#include <sys/stat.h>
#include <unistd.h>
#include "DeviceStatusServer.h"
#include "Protocol/ProtocolApi.h"

namespace fs = std::filesystem;

using namespace Protocol;

DeviceStatusServer::Ptr DeviceStatusServer::instance(){
    static auto ptr = std::make_shared<DeviceStatusServer>();
    return ptr;
}

DeviceStatusServer::DeviceStatusServer(){
    RegistRPC();
}

DeviceStatusServer::~DeviceStatusServer(){

}

void DeviceStatusServer::RegistRPC(){
    RPCMethodMap method_map;

    method_map.emplace("Get", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Get(request, inMap, response, outMap);
	}));
	
	IProtocolInterface::GetInstance()->RegistProtocol("DeviceStatus", method_map);
}

double GetCurrentCPUUsage(){
    std::ifstream statFile("/proc/stat");
    if (!statFile.is_open()) {
        return -1.0; // 打开文件失败
    }

    std::string line;
    std::getline(statFile, line);
    if (line.find("cpu") != 0) {
        return -1.0; // 第一行不包含CPU信息
    }

    // 解析CPU时间信息
    unsigned long long user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
    if (sscanf(line.c_str(), "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
               &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest, &guest_nice) != 10) {
        return -1.0; // 解析失败
    }

    unsigned long long total = user + nice + system + idle + iowait + irq + softirq + steal;
    unsigned long long idleTotal = idle + iowait;
    double cpuUsage = 100.0 * (1.0 - static_cast<double>(idleTotal) / total);
    return cpuUsage;
}

// 获取内存信息
bool GetMemoryInfo(unsigned long long& totalMemory, unsigned long long& freeMemory) {
    std::ifstream meminfo("/proc/meminfo");
    if (!meminfo.is_open()) {
        return false; // 打开文件失败
    }

    std::string line;
    while (std::getline(meminfo, line)) {
        if (line.find("MemTotal:") != std::string::npos) {
            //KB
            if (sscanf(line.c_str(), "MemTotal: %llu kB", &totalMemory) != 1) {
                return false; // 解析失败
            }
        } else if (line.find("MemAvailable:") != std::string::npos) {
            if (sscanf(line.c_str(), "MemAvailable: %llu kB", &freeMemory) != 1) {
                return false; // 解析失败
            }
        }
    }

    // tracef(" totalMemory %llu,  freeMemory %llu", totalMemory,freeMemory);
    //MB
    totalMemory = totalMemory/1024;
    freeMemory = freeMemory/1024;
    return true;
}


bool isMountPoint(const char* directory) {
    struct stat st1, st2;

    // 获取目标目录的 stat 信息
    if (stat(directory, &st1) != 0) {
        // 如果无法获取 stat 信息，可以认为不是独立的挂载点
        return false;
    }

    // 获取目标目录的父目录的 stat 信息
    char parentDirectory[PATH_MAX];
    snprintf(parentDirectory, PATH_MAX, "%s/..", directory);
    if (stat(parentDirectory, &st2) != 0) {
        // 如果无法获取 stat 信息，可以认为不是独立的挂载点
        return false;
    }

    // 比较两个 stat 信息的设备号是否一致
    return st1.st_dev != st2.st_dev;
}

bool GetSDStorage(unsigned long long & total, unsigned long long & free){
    std::string sd_path = "/mnt/sd";
    if(!isMountPoint(sd_path.c_str())){
        errorf("/mnt/sd  is not mount");
        total = free = 0;
        return false;
    }
    fs::path mountPoint = sd_path;  // 替换为你的挂载点路径
    fs::space_info space = fs::space(mountPoint);

    // std::cout << "Available space on " << mountPoint << ":" << std::endl;
    // std::cout << "Capacity: " << space.capacity << " bytes" << std::endl;
    // std::cout << "Free: " << space.free << " bytes" << std::endl;
    // std::cout << "Available: " << space.available << " bytes" << std::endl;

    // tracef(" GetSDStorage  total  %llu free %llu ", space.capacity, space.available);

    total = space.capacity/(1024*1024*1024);
    free = space.available/(1024*1024*1024);

    return true;
}

bool DeviceStatusServer::Get(const Json::Value &request, const Fdt::BufferMap::Ptr &inMap, Json::Value &response, Fdt::BufferMap::Ptr &outMap){
    //获取当前cpu占用信息
    double cpu_info = GetCurrentCPUUsage();
    //获取当前内存占用信息
    unsigned long long total_mem, free_mem;
    GetMemoryInfo(total_mem, free_mem);
    //获取当前sd卡存储使用信息
    unsigned long long storage_total, storage_free;
    GetSDStorage(storage_total, storage_free);

    tracef(" cpu %f,  total_mem %llu, free_mem %llu, storage_total %llu, storage_free %llu", cpu_info, total_mem, 
     free_mem, storage_total, storage_free);

    response["data"]["Param"]["Cpu"] = (int)(cpu_info*100)%100;
    response["data"]["Param"]["Mem"]["total"] = total_mem;
    response["data"]["Param"]["Mem"]["free"] = free_mem;

    response["data"]["Param"]["SDStorage"]["total"] = storage_total;
    response["data"]["Param"]["SDStorage"]["free"] = storage_free;
    
    return true;
}